﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Net;
using System.Threading;

namespace Innovox.YDeviceLib
{


    public enum ModemAccessType
    {
        Master,
        Repeater,
        RepeaterNode,
        Node,
        Unknown
    }

    public enum ModemCouplingType
    {
        Inductive,
        Coax,
        Unknown
    }

    public enum ModemUpdateState
    {
        Downloading,
        Completed,
        Failed,
        Unknown
    }

    public class DS2ModemCreationException : Exception
    {
        new public string Message { get;private set; }

        public DS2ModemCreationException(string description)
        {
            Message = description;
        }
    }

    public class ModemUpdateProgressedEventArgs : EventArgs
    {
        public ModemUpdateState State { get; set; }
        public int BytesDone { get; set; }

        public ModemUpdateProgressedEventArgs()
        {

        }
    }

    /// <summary>
    /// 
    /// </summary>
    public class DS2Modem
    {
        // Fired when firmware upgrade has progressed
        public event EventHandler<ModemUpdateProgressedEventArgs> ModemUpgradeProgressed;

        static int consolePort = 40000;
        static public int ConsolePort { get { return consolePort; } set { consolePort = value; } }

        static int tunnelPort = 40044;
        static public int TunnelPort { get { return tunnelPort; } set { tunnelPort = value; } }

        private IPAddress _ip;

        public ModemAccessType AccesType { get; set; }
        public ModemCouplingType CouplingType { get; private set; }
        string _macAddress;
        public string MacAddress { get { return _macAddress; } set { _macAddress = value; } }
        string _ipAddress;
        public string IpAddress { get { return _ipAddress; } private set { _ipAddress = value; } }
        public int TxBitrate { get; set; }
        public int RxBitrate { get; set; }
        public List<string> Childs { get; private set; }
        public string Parent { get; private set; }
        const string _password = "maxibon";//"adomis";
        public string ServerIp { get; set; }
        public string FirmwareFilename { get; set; }
        public string Ds2Version { get; set; }
        public int Level { get; set; }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="info">DS2 modem i command response string</param>
        public DS2Modem(IPAddress ip)
        {
            Childs = new List<string>();
            _macAddress = "";
            _ipAddress = "";
            _ip = ip;
            Level = -1;
            AccesType = ModemAccessType.Unknown;
            //if (ParseConsoleInfo(info) == false)
             //   throw new DS2ModemCreationException("DS2 modem Information parsing error");
        }

        static Dictionary<ModemAccessType, string> AccessTypeNames = new Dictionary<ModemAccessType, string>() { 
        { ModemAccessType.Master, "Rx Master" }, { ModemAccessType.Repeater, "Rx Repeater" },
        {ModemAccessType.RepeaterNode,"Repeater Node"},{ModemAccessType.Node,"Node"},{ModemAccessType.Unknown,"Unknown"}};

        public string GetAccessTypeName(ModemAccessType access)
        {
            return AccessTypeNames[access];
        }

        public string AccessTypeName { get{return AccessTypeNames[AccesType];}}

        static public bool Ping(IPAddress ip)
        {
            System.Net.NetworkInformation.PingReply pr = Innovox.NetTools.NetScan.Ping(ip);

            return (pr.Status == System.Net.NetworkInformation.IPStatus.Success);
        }

        const int _defaultTimeout = 20000;

        public bool UpdateFirmware()
        {
            int tries = 0;
            int prevBytesDone = 0;
            //string pwStr = string.Format("Password:??");
            DS2Socket socket = new DS2Socket(_ip, DS2Modem.ConsolePort, false, _defaultTimeout);
            //System.Net.NetworkInformation.PingReply pr = Innovox.NetTools.NetScan.Ping(_ip);

            //if (pr.Status == System.Net.NetworkInformation.IPStatus.Success)
            while (true)
            {
                if (socket.Connect())
                {
                    tries = 0;
                    while (tries < 10)
                    {
                        string response = "";
                        Thread.Sleep(50);

                        if (socket.Send("i\r\n", "#user@/>", out response) == true)
                        {
                            if (response.EndsWith("OK\n#user@/>") || response.EndsWith("OK\n#admin@/>"))
                            {
                                Thread.Sleep(50);

                                if (socket.Send("mode admin\r\n", "Password:", out response) == true)
                                {
                                    string response2 = "";
                                    Thread.Sleep(50);

                                    if (socket.Send(_password + "\r\n", "#admin@/>", out response2) == true)
                                    {
                                        Thread.Sleep(50);
                                        //FirmwareFilename = "de95_v1_x_flash-ALMAv5_0_15_0_0_cvs_38400-ami.ftp";
                                        //if (socket.Send("flup u RAW 0 " + ServerIp + " " + FirmwareFilename + "\r\n", "Upgrade process starting", out response) == true)
                                        if (socket.Send("flup u firmware 0 " + ServerIp + " " + FirmwareFilename + "\r\n", "Upgrade process starting", out response) == true)
                                        {
                                            tries = 0;
                                            while (tries < 10)
                                            {
                                                Thread.Sleep(2000);
                                                if (socket.Send("flup sh\r\n", "#admin@/>", out response) == true)
                                                {
                                                    ModemUpdateState state = ModemUpdateState.Unknown;
                                                    int bytesDone = 0;

                                                    if (response.Contains("Upgrade process is downloading image"))
                                                    {
                                                        state = ModemUpdateState.Downloading;
                                                        int temp = ParseUpdateProgress(response);
                                                        bytesDone = temp - prevBytesDone;
                                                        prevBytesDone = temp;
                                                    }
                                                    else if (response.Contains("Finished correctly"))
                                                    {
                                                        /* eliminated for parcial download
                                                        string formatedMac = _macAddress.Replace(":", " 0x");
                                                        Thread.Sleep(200);
                                                        if (socket.Send("sys mac c 0x" + formatedMac + "\r\n", "#admin@/>", out response) == true)
                                                        {
                                                            if (response.Contains("MAC Address changed"))
                                                            {
                                                                if (socket.Send("dhcp dhcp on\r\n", "#admin@/>", out response) == true)
                                                                {
                                                                    state = ModemUpdateState.Completed;
                                                                    //socket.Close();
                                                                    //return true;
                                                                }
                                                            }
                                                        }
                                                         */
                                                        // partial download
                                                        Thread.Sleep(200);
                                                        state = ModemUpdateState.Completed;
                                                    }
                                                    else if (response.Contains("Failed")) //. Failed downloading file"))
                                                    {//Failed. Failed downloading file (-12)
                                                        state = ModemUpdateState.Failed;
                                                        //socket.Close();
                                                        //return false;
                                                    }
                                                    else
                                                    {
                                                        tries++;
                                                        continue;
                                                    }

                                                    tries = 0;

                                                    if (ModemUpgradeProgressed != null)
                                                    {
                                                        ModemUpdateProgressedEventArgs progArg = new ModemUpdateProgressedEventArgs();
                                                        progArg.BytesDone = bytesDone;
                                                        progArg.State = state;
                                                        ModemUpgradeProgressed(this, progArg);
                                                    }

                                                    if (state == ModemUpdateState.Failed)
                                                    {
                                                        socket.Close();
                                                        return false;
                                                    }
                                                    else if (state == ModemUpdateState.Completed)
                                                    {
                                                        socket.Close();
                                                        return true;
                                                    }

                                                }
                                                else
                                                    tries++;
                                                Thread.Sleep(8000);
                                            }
                                        }
                                        socket.Close();
                                        return false;
                                    }

                                }
                            }
                        }
                        tries++;
                    }
                }
                else
                {
                    Thread.Sleep(200);
                    tries++;
                }
                if (tries > 5)
                {
                    if (socket != null)
                        socket.Close();
                    return false;
                }
            }
            if(socket != null)
                socket.Close();

            return false;
        }

        public bool EnterAdminMode(DS2Socket socket)
        {
            int tries = 0;

            while (tries < 3)
            {
                string response = "";
                Thread.Sleep(200);

                if (socket.Send("\r\n", "#user@/>", out response) == true)
                {
                    if (response.EndsWith("#user@/>") || response.EndsWith("#admin@/>"))
                    {
                        Thread.Sleep(200);

                        if (socket.Send("mode admin\r\n", "Password:", out response) == true)
                        {
                            string response2 = "";
                            Thread.Sleep(200);

                            if (socket.Send(_password + "\r\n", "#admin@/>", out response2) == true)
                                return true;
                        }
                    }
                }
                tries++;
            }
            return false;
        }

        public bool ChangeMAC()
        {
            int tries = 0;
            //string pwStr = string.Format("Password:??");
            DS2Socket socket = new DS2Socket(_ip, DS2Modem.ConsolePort, false, _defaultTimeout);
            //System.Net.NetworkInformation.PingReply pr = Innovox.NetTools.NetScan.Ping(_ip);

            //if (pr.Status == System.Net.NetworkInformation.IPStatus.Success)
            while (tries < 3)
            {
                if (socket.Connect())
                {
                    tries = 0;
                    while (tries < 3)
                    {
                        string response = "";
                        Thread.Sleep(200);

                        if (socket.Send("\r\n", "#user@/>", out response) == true)
                        {
                            Thread.Sleep(200);
                            if (response.EndsWith("#user@/>") || response.EndsWith("#admin@/>"))
                            {
                                if (socket.Send("ver\r\n", "#user@/>", out response) == true)
                                {
                                    string[] ds2VerString = response.Split(new char[]{'\n'});

                                    Ds2Version = "";
                                    if (ds2VerString[0].StartsWith("FIRMWARE VERSION"))
                                    {
                                        Ds2Version = ds2VerString[1];
                                        Thread.Sleep(200);

                                        if (socket.Send("mode admin\r\n", "Password:", out response) == true)
                                        {
                                            string response2 = "";
                                            Thread.Sleep(200);

                                            if (socket.Send(_password + "\r\n", "#admin@/>", out response2) == true)
                                            {
                                                Thread.Sleep(200);
                                                //FirmwareFilename = "de95_v1_x_flash-ALMAv5_0_15_0_0_cvs_38400-ami.ftp";
                                                string formatedMac = _macAddress.Replace(":", " 0x");
                                                Thread.Sleep(400);
                                                if (socket.Send("sys mac c 0x" + formatedMac + "\r\n", "#admin@/>", out response) == true)
                                                {
                                                    if (response.Contains("MAC Address changed"))
                                                    {
                                                        if (socket.Send("dhcp dhcp on\r\n", "#admin@/>", out response) == true)
                                                        {
                                                            //state = ModemUpdateState.Completed;
                                                            socket.Close();
                                                            return true;
                                                        }
                                                        else if (response.Contains("Failed")) //. Failed downloading file"))
                                                        {//Failed. Failed downloading file (-12)
                                                            //state = ModemUpdateState.Failed;
                                                            //socket.Close();
                                                            //return false;
                                                            continue;
                                                        }
                                                    }
                                                }
                                            }
                                            //socket.Close();
                                            //return false;
                                        }
                                    }
                                }
                            }
                        }
                        tries++;
                    }
                    break;
                }
                else
                    tries++;
            }
            if (socket != null)
                socket.Close();

            return false;
        }

        static int accessTypeChangeTimeout = 20000;

        public bool ChangeAccessType(ModemAccessType accessType)
        {
            int tries = 0;
            //string pwStr = string.Format("Password:??");
            DS2Socket socket = new DS2Socket(_ip, DS2Modem.ConsolePort, false, accessTypeChangeTimeout);
            System.Net.NetworkInformation.PingReply pr = Innovox.NetTools.NetScan.Ping(_ip);

            if (pr.Status == System.Net.NetworkInformation.IPStatus.Success)
            {
                if (socket.Connect())
                {
                    if( EnterAdminMode(socket) == true )
                    {
                        //while (tries < 3)
                        {
                            string response = "";
                            Thread.Sleep(200);

                            string cmd = "m c n ";
                            if (accessType == ModemAccessType.Master)
                                cmd += "m";
                            else if (accessType == ModemAccessType.Repeater)
                                cmd += "r";
                            else
                                return false;

                            Thread.Sleep(400);
                            if (socket.Send(cmd + "\r\n", "#admin@/>", out response) == true)
                            {
                                string outStr = "Initializing MAC in ACCESS mode and as ";
                                if (accessType == ModemAccessType.Master)
                                    outStr += "MASTER";
                                else if (accessType == ModemAccessType.Repeater)
                                    outStr += "TDREPEATER";

                                if (response.Contains(outStr))
                                {
                                    this.AccesType = accessType;
                                    socket.Close();
                                    return true;
                                }
                            }
                            tries++;
                        }
                        socket.Close();
                        return false;
                    }
                }
            }
            if (socket != null)
                socket.Close();

            return false;
        }

        public string GetCouplingName()
        {
            if (CouplingType == ModemCouplingType.Inductive)
                return "Inductive";
            else if (CouplingType == ModemCouplingType.Coax)
                return "Coax";
            else
                return "Unknown";

        }

        public string GetNotSelectedCouplingName()
        {
            if (CouplingType == ModemCouplingType.Inductive)
                return "Coax";
            else if (CouplingType == ModemCouplingType.Coax)
                return "Inductive";
            else
                return "";

        }

        public bool ChangeCouplingType(ModemCouplingType couplingType)
        {
            DS2Socket socket = new DS2Socket(_ip, DS2Modem.ConsolePort, false, accessTypeChangeTimeout);
            System.Net.NetworkInformation.PingReply pr = Innovox.NetTools.NetScan.Ping(_ip);

            if (pr.Status == System.Net.NetworkInformation.IPStatus.Success)
            {
                if (socket.Connect())
                {
                    if (EnterAdminMode(socket) == true)
                    {
                        string response = "";
                        Thread.Sleep(200);

                        string cmd = "slc s ";
                        if (couplingType == ModemCouplingType.Coax)
                            cmd += "COAX";
                        else if (couplingType == ModemCouplingType.Inductive)
                            cmd += "IND";
                        else
                            return false;

                        Thread.Sleep(400);
                        if (socket.Send(cmd + "\r\n", "#admin@/>", out response) == true)
                        {
                            string outStr = "Switched to ";
                            if (couplingType == ModemCouplingType.Coax)
                                outStr += "COAX";
                            else if (couplingType == ModemCouplingType.Inductive)
                                outStr += "IND";

                            if (response.Contains(outStr))
                            {
                                this.CouplingType = couplingType;
                                socket.Close();
                                return true;
                            }
                        }
                        socket.Close();
                        return false;
                    }
                }
            }
            if (socket != null)
                socket.Close();

            return false;
        }

        public bool Reset()
        {
            int tries = 0;
            //string pwStr = string.Format("Password:??");
            DS2Socket socket = new DS2Socket(_ip, DS2Modem.ConsolePort, false, _defaultTimeout);
            System.Net.NetworkInformation.PingReply pr = Innovox.NetTools.NetScan.Ping(_ip);

            if (pr.Status == System.Net.NetworkInformation.IPStatus.Success)
            {
                if (socket.Connect())
                {
                    while (tries < 10)
                    {
                        string response = "";
                        Thread.Sleep(50);

                        if (socket.Send("\r\n", "#user@/>", out response) == true)
                        {
                            if (response.EndsWith("#user@/>") || response.EndsWith("#admin@/>"))
                            {
                                Thread.Sleep(50);

                                if (socket.Send("mode admin\r\n", "Password:", out response) == true)
                                {
                                    string response2 = "";
                                    Thread.Sleep(50);

                                    if (socket.Send(_password + "\r\n", "#admin@/>", out response2) == true)
                                    {
                                        socket.Send("hw rst\r\n");
                                        socket.Close();
                                        return true;
                                    }

                                }
                            }
                        }
                        tries++;
                    }
                }
            }
            if (socket != null)
                socket.Close();

            return false;
        }

        public static DS2Modem Create(IPAddress ip)
        {
            string response = "";
            DS2Socket socket = new DS2Socket(ip, DS2Modem.ConsolePort, false, _defaultTimeout);
            DS2Modem result= null;

            if (socket.Connect() == true)
            {
                int retries = 3;

                while (retries > 0)
                {
                    if (socket.Send("i\r\n", "#user@/>", out response) == true)
                    {
                        DS2Modem m = new DS2Modem(ip);
                        if (ParseConsoleInfo(m, response) == true)
                        {
                            if (m.AccesType == ModemAccessType.Repeater)
                            {
                                DS2Socket socketTunnel = new DS2Socket(ip, DS2Modem.tunnelPort, true, _defaultTimeout);
                                if (socketTunnel.Connect() == true)
                                    m.AccesType = ModemAccessType.Node;
                                socketTunnel.Close();
                            }
                            Thread.Sleep(200);
                            result = m;
                            if (m.EnterAdminMode(socket) == true)
                            {
                                response = "";
                                Thread.Sleep(200);

                                string cmd = "slc i";

                                Thread.Sleep(400);
                                if (socket.Send(cmd + "\r\n", "#admin@/>", out response) == true)
                                {
                                    if (response.Contains("Coupling to COAX"))
                                        m.CouplingType = ModemCouplingType.Coax;
                                    else if (response.Contains("Coupling to IND"))
                                        m.CouplingType = ModemCouplingType.Inductive;
                                    else
                                        m.CouplingType = ModemCouplingType.Unknown;
                                }
                            }
                            else
                                m.CouplingType = ModemCouplingType.Unknown;
                        }
                    }

                    if (result != null)
                        break;
                    retries--;
                    Thread.Sleep(300);
                }
            }
            socket.Close();
            return result;
        }

        public bool UpdateInfo()
        {
            bool result = false;
            string response = "";
            DS2Socket socket = new DS2Socket(this._ip, DS2Modem.ConsolePort, true, _defaultTimeout);

            if (socket.Connect() == true)
            {
                UpdateRepeaterAccessType();

                if (socket.Send("i\r\n", "#user@/>", out response) == true)
                {
                    if (ParseConsoleInfo(this, response) == true)
                    {
                        result = true;
                    }
                }
            }
            if (result == false)
            {
                TxBitrate = 0;
                RxBitrate = 0;
            }
            socket.Close();
            return result;
        }

        private void UpdateRepeaterAccessType()
        {
            if (AccesType == ModemAccessType.Repeater)
            {
                DS2Socket socketTunnel = new DS2Socket(this._ip, DS2Modem.tunnelPort, true, _defaultTimeout);
                if (socketTunnel.Connect() == true)
                    AccesType = ModemAccessType.RepeaterNode;
                socketTunnel.Close();
            }
        }

        /// <summary>
        /// Parse the DS2 i command response, the results are saved in
        /// the DS2Modem properties
        /// </summary>
        /// <param name="inf">DS2 modem i command response string</param>
        /// <returns>true if success</returns>
        private static bool ParseConsoleInfo(DS2Modem m, string inf)
        {
            m.Childs.Clear();

            if (inf == null)
                return false;
            
            TryParseMasterBitrate(m, inf);

            if (m.AccesType == ModemAccessType.Unknown)
            {
                if (inf.Contains("Master Access"))
                {
                    m.AccesType = ModemAccessType.Master;

                    //if (TryParseMasterBitrate(m, inf) == false)
                    //    return false;
                }
                else if (inf.Contains("Repeater Access"))
                    m.AccesType = ModemAccessType.Repeater;
                else
                {
                    m.AccesType = ModemAccessType.Unknown;
                    return false;
                }
            }

            if (TryParseMAC(m, inf) == false)
                return false;

            if (TryParseIP(m, inf) == false)
                return false;

            if (TryParseModemTable(m,inf) == false)
                return false;

            return true;

        }

        /// <summary> 
        /// Validate and extract a MAC address from a string. 
        /// </summary> 
        /// <param name="macAddress">Mac Address.</param>
        /// <param name="result">Result string</param>
        /// <returns>string MACAddress or null string if not valid</returns> 
        public static bool TryParseMAC(DS2Modem modem, string macAddress)
        {
            Regex rx = new Regex(@"MAC:\s*(?<MAC>(([0-9a-fA-F][0-9a-fA-F][-:]){5}([0-9a-fA-F][0-9a-fA-F])))", RegexOptions.IgnoreCase);
            Match m = rx.Match(macAddress);
            bool valid = false;

            modem.MacAddress = m.Groups["MAC"].Value;
            if (modem.MacAddress.Length == 17)
                valid = true;
            else
            {
                rx = new Regex(@"MAC:\s*(?<MAC>(([0-9a-fA-F][0-9a-fA-F]){5}([0-9a-fA-F][0-9a-fA-F])))", RegexOptions.IgnoreCase);
                Match m2 = rx.Match(macAddress);
                modem.MacAddress = m2.Groups["MAC"].Value;
                if (modem.MacAddress.Length == 12)
                {
                    valid = true;
                }
            }

            return valid;
        }

        /// <summary>
        /// Validate and extract an IP address from a string. 
        /// </summary>
        /// <param name="addr">Input string</param>
        /// <param name="result">Result string</param>
        /// <returns>true if successfull</returns>
        public static bool TryParseIP(DS2Modem modem, string addr)
        {
            string pattern = @"IP:\s*(?<IP>(([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}))\n";
            //create our Regular Expression object
            Regex rx = new Regex(pattern);
            Match m = rx.Match(addr);

            modem.IpAddress = m.Groups["IP"].Value;

            bool valid = false;

            if (m.Success == true)
                valid = true;

            return valid;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static bool TryParseModemTable(DS2Modem modem, string input)
        {
            string pattern = @"AVAILABLE CONNECTIONS:((.|\n)*)(?<TABLE>((.|\n)*))Number of boots:";
            //create our Regular Expression object
            Regex rx = new Regex(pattern);
            Match m = rx.Match(input);

            string tableStr = m.Groups[1].Value;

            bool valid = false;

            if (m.Success == true)
            {
                valid = modem.TryParseModemTableItems(tableStr);
            }

            return valid;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public bool TryParseModemTableItems(string input)
        {
            //create match pattern
           // string test = "----------------------------------------------------------------------------------\n EXTA:    100 Mbps        Forwarding\n EXTB:    100 Mbps        Forwarding\n-------------------------------------------------------------------------------\n         MAC            PHY TX XPUT    PHY RX XPUT   BR STATE  STATE  NODE TYPE  \n-------------------------------------------------------------------------------\n 9. 00:50:C2:12:6B:4B      1 Mbps (H)     5 Mbps         Forwarding   A      TDREP\n10. B8:EE:79:00:10:89      2 Mbps         3 Mbps         Forwarding   A      TDREP\n";
            string pattern = @"(?<PORT>[0-9]{1,3}\.)\s*(?<MAC>(([0-9a-fA-F][0-9a-fA-F][-:]){5}([0-9a-fA-F][0-9a-fA-F])))\s*(?<TXRATE>[0-9]{1,3})\s*Mbps.*\s(?<RXRATE>[0-9]{1,3})\s*Mbps.*(?<STATE>((\(M\))|(\sA\s)))";
            //create our Regular Expression object
            Regex rx = new Regex(pattern);
            MatchCollection mc = rx.Matches(input);

            foreach (Match m in mc)
            {
                if (m.Groups["STATE"].Value == "(M)")
                {
                    Parent = m.Groups["MAC"].Value;
                    this.TxBitrate = int.Parse(m.Groups["TXRATE"].Value);
                    this.RxBitrate = int.Parse(m.Groups["RXRATE"].Value);
                }
                else
                    Childs.Add(m.Groups["MAC"].Value);
            }
            bool valid = false;

            //if (m.Success == true)
            valid = true;

            return valid;
        }

        public static bool TryParseMasterBitrate(DS2Modem modem, string input)
        {
            //create match pattern
            string pattern = @"EXT(A|B):\s*(?<BITRATE>([0-9]{1,3}))\s*Mbps";
            //create our Regular Expression object
            Regex rx = new Regex(pattern);
            Match m = rx.Match(input);

            bool valid = false;

            if (m.Success == true)
            {
                int bitrate = int.Parse(m.Groups["BITRATE"].Value);
                modem.RxBitrate = bitrate;
                modem.TxBitrate = bitrate;
                valid = true;
            }

            return valid;
        }

        public static int ParseUpdateProgress(string input)
        {
            //create match pattern
            string pattern = @"Total\sCompleted\s=\s*(?<BYTEDONE>([0-9]{1,8}))\s*/([0-9]{1,8})\s";
            //create our Regular Expression object
            Regex rx = new Regex(pattern);
            Match m = rx.Match(input);
            int progress = -1;

            if (m.Success == true)
                progress = int.Parse(m.Groups["BYTEDONE"].Value);

            return progress;
        }
    }
}
